from __future__ import absolute_import, division

from .base import *


class Icon(PandaNodePath):
    icon = Attribute(initial = None, writable = True, changed = lambda self: self.update_icon())
    
    texture = Attribute(initiable = None, writable = True, changed = lambda self: self.update_texture())
    
    def set_icon(self, icon):
        self.icon = icon
    
    @property
    def full_texture_name(self):
        if self.icon.startswith('UI '):
            return self.icon
        else:
            return 'UI Icon ' + self.icon
    
    @property
    def width(self):
        return self.texture.getXSize()
    
    @property
    def height(self):
        return self.texture.getYSize()
    
    @property
    def area(self):
        return (self.x - math.floor(self.width  / 2),
                self.x + math.ceil (self.width  / 2),
                self.y - math.floor(self.height / 2),
                self.y + math.ceil (self.height / 2))
    
    @property
    def new_node(self):
        cm = CardMaker(self.id)
        cm.setFrame(-0.5, 0.5, -0.5, 0.5)
        
        return cm.generate()
    
    def setup_new_node(self):
        self.update_texture()
    
    def update_motion_dependent(self):
        super(Icon, self).update_motion_dependent()
        
        self.update_texture()
    
    def update_icon(self):
        self.texture = None
    
    def update_texture(self):
        if self.node is None or self.icon is None:
            return
        
        if self.texture is None:
            self.texture = self.resources.load_gui_texture(self.full_texture_name)
        
        self.node_path.setTexture(self.texture)
        
        if self.screen.is_initialized:
            self.node_path.setScale(self.screen.width_from_pixels(self.width), 1,
                                    self.screen.height_from_pixels(self.height))


class Label(PandaNodePath):
    text        = Attribute(initial =  None, writable = True, changed = lambda self: self.update_text())
    text_align  = Attribute(initial =   '<', writable = True, changed = lambda self: self.update_text_align())
    font_size   = Attribute(initial =    16, writable = True)
    is_quantity = Attribute(initial = False, writable = True)
    
    @property
    def new_node(self):
        return TextNode(self.id)
    
    def setup_new_node(self):
        self.node.setFont(self.resources.load_font('FreeSans'))
        self.node.setTextColor(0, 0, 0, 1)
        
        self.update_text_align()
        self.update_text()
    
    def update_motion_dependent(self):
        super(Label, self).update_motion_dependent()
        
        self.update_font_size()
    
    def update_font_size(self):
        self.node_path.setScale(self.screen.width_from_pixels(self.font_size), 1,
                                self.screen.height_from_pixels(self.font_size))

    def update_text(self):
        if self.node is None:
            return
        
        if self.text is None:
            self.node.setText('')
        elif self.is_quantity:
            self.node.setText('{:,}'.format(self.text).replace(',', ' '))
        else:
            self.node.setText(str(self.text))

    def update_text_align(self):
        if self.node is None:
            return
        
        self.node.setAlign({'<': TextNode.ALeft,
                            '|': TextNode.ACenter,
                            '>': TextNode.ARight}.get(self.text_align))


class QuantityLabel(Label):
    text_align  =_ ('>')
    is_quantity =_ (True)


class Tooltip(Label):
    def setup_new_node(self):
        super(Tooltip, self).setup_new_node()
        
        margin = 0.6
        
        self.node.setFrameColor(0.25, 0.25, 0.25, 1)
        self.node.setCardColor(1, 1, 1, 0.25)
        self.node.setFrameAsMargin(margin, margin, margin, margin)
        self.node.setCardAsMargin(margin, margin, margin, margin)
        self.node.setCardDecal(True)


class Heading(PandaNodePath):
    font_size = Attribute(initial  = 16)
    text      = Attribute(writable = True)
    icon      = Attribute(writable = True, changed = lambda self: self.icon_child is not None and self.icon_child.set_icon(self.icon))
    offset    = Attribute(initial  = ( 10,  5))
    
    label_child = Attribute(initiable = False)
    icon_child  = Attribute(initiable = False)
    
    def setup_new_node(self):
        self.label_child = Label(self.id + '.label', self.offset, font_size = self.font_size)
        self.label_child.create_in(self)
        
        self.icon_child = Icon(self.id + '.icon', (0, 0), icon = self.icon)
        self.icon_child.create_in(self)
    
    def update_motion_dependent(self):
        super(Heading, self).update_motion_dependent()
        
        self.label_child.update_motion_dependent()
        self.icon_child .update_motion_dependent()
    
    def on_update(self):
        self.label_child.text = self.text
        
        self.label_child.update()
        self.icon_child .update()



class Button(PandaNodePath, Observable):
    texture       =_ ('UI Button')
    pressed_delta =_ (0, 0)
    
    icon           = Attribute(initial = None, writable = True, changed = lambda self: self.update_icon())
    action         = Attribute(initial = None, writable = True)
    maintain_state = Attribute(initial = False, writable = True)
    group          = Attribute(initial = None)
    data           = Attribute(initial = None)
    
    normal_child  = Attribute(initiable = False)
    hover_child   = Attribute(initiable = False)
    pressed_child = Attribute(initiable = False)
    width         = normal_child._.width
    height        = normal_child._.height
    
    icon_child         = Attribute(initiable = False)
    pressed_icon_child = Attribute(initiable = False)
    
    is_pressed   = Attribute(initial = False, initiable = False, writable = True,
                             changed = lambda self: self.update_state())
    is_hover     = Attribute(initial = False, initiable = False, writable = True,
                             changed = lambda self: self.update_state())
    is_locked_in = Attribute(initial = False, initiable = False, writable = True,
                             changed = lambda self: self.update_state())
    
    def setup(self):
        if self.group is not None:
            self.group.add_button(self)
    
    @property
    def area(self):
        return (self.normal_child.left   + self.x,
                self.normal_child.right  + self.x,
                self.normal_child.top    + self.y,
                self.normal_child.bottom + self.y)
    
    def setup_new_node(self):
        self.update_children()
    
    def update_motion_dependent(self):
        super(Button, self).update_motion_dependent()
        
        self.update_children()
        
        self.normal_child .update_motion_dependent()
        self.hover_child  .update_motion_dependent()
        self.pressed_child.update_motion_dependent()
        
        if self.icon is not None:
            self.icon_child        .update_motion_dependent()
            self.pressed_icon_child.update_motion_dependent()
        
        self.update_state()
    
    def update_icon(self):
        if self.icon_child is not None:
            self.icon_child.icon = self.icon
    
    def update_children(self):
        if self.node is None:
            return
        
        if self.normal_child is None:
            self.normal_child = Icon(self.id + '.normal', (0, 0), icon = self.texture + ' Normal')
            self.normal_child.create_in(self)
        
        if self.hover_child is None:
            self.hover_child = Icon(self.id + '.hover', (0, 0), icon = self.texture + ' Hover')
            self.hover_child.create_in(self)
        
        if self.pressed_child is None:
            self.pressed_child = Icon(self.id + '.pressed', (0, self.pressed_delta[0]), icon = self.texture + ' Pressed')
            self.pressed_child.create_in(self)
        
        if self.icon_child is None and self.icon is not None:
            self.icon_child = Icon(self.id + '.icon', (0, 0), icon = self.icon)
            self.icon_child.create_in(self)
        
        if self.pressed_icon_child is None and self.icon is not None:
            self.pressed_icon_child = Icon(self.id + '.icon.pressed', (0, self.pressed_delta[1]), icon = self.icon)
            self.pressed_icon_child.create_in(self)
    
    def update_state(self):
        if self.normal_child is None:
            return
        
        self.normal_child .visible = (not self.is_pressed or not self.is_hover) and not self.is_locked_in
        self.hover_child  .visible = (not self.is_pressed and    self.is_hover) and not self.is_locked_in
        self.pressed_child.visible = (    self.is_pressed and    self.is_hover) or      self.is_locked_in
        
        if self.icon is not None:
            self.icon_child        .visible = not self.pressed_child.visible
            self.pressed_icon_child.visible =     self.pressed_child.visible
    
    def lock_in(self):
        self.is_locked_in = True
    
    def release(self):
        self.is_locked_in = False
    
    def on_mouse_down(self):
        self.is_pressed = True
    
    def on_mouse_up(self):
        self.is_pressed = False
    
    def on_clicked(self):
        if self.maintain_state:
            self.is_locked_in = True
        
        self.broadcast(self)
        
        if self.action is not None:
            self.action()
    
    def on_update(self):
        self.is_hover = self.has_mouse


class StateButton(Button):
    maintain_state = True


class TabButton(StateButton):
    texture        = 'UI Button Tab'
    pressed_delta  = (1, 3)


class ButtonGroup(Object):
    buttons = SetAttribute(initiable = False)
    current = Attribute(initiable = False)
    
    @property
    def has_current(self):
        return self.current is not None
    
    def add_button(self, button):
        button.add_observer(self.set_current)
        
        self._buttons.add(button)
    
    def set_current(self, button):
        if self.current is not None:
            self.current.release()
        
        self._current = button


class TabFolder(PandaNodePath):
    tab_position = Attribute()
    tab_delta    = Attribute()
    
    current_page = Attribute(initiable = False, writable = True)
    pages        = DictAttribute(initiable = False)
    
    @property
    def next_tab_position(self):
        return (self.tab_position[0] + len(self.pages) * self.tab_delta,
                self.tab_position[1])
    
    def add_tab(self, id, icon):
        self._pages[id] = TabPage(self.id + '.' + id, (0, 0),
                                  folder       = self,
                                  tab_position = self.next_tab_position,
                                  icon         = icon)
        
        self._pages[id].create_in(self)
        
        if self.current_page is None:
            self.show_tab(self._pages[id])
        
        return self._pages[id]
    
    def show_tab(self, tab):
        if self.current_page is not None:
            self.current_page.deactivate()
        
        self.current_page = tab
        self.current_page.activate()
    
    def update_motion_dependent(self):
        super(TabFolder, self).update_motion_dependent()
        
        for page in self.pages.values():
            page.update_motion_dependent()
    
    def on_update(self):
        for page in self.pages.values():
            page.update()


class TabPage(PandaNodePath):
    folder       = Attribute()
    tab_position = Attribute()
    icon         = Attribute()
    button       = Attribute(initiable = False)
    pane         = Attribute(initiable = False)
    add_item     = pane._.add_item
    items        = pane._.items
    
    def setup_new_node(self):
        self.button = TabButton(self.id + '.button', self.tab_position,
                                icon   = self.icon,
                                action = lambda: self.folder.show_tab(self))
        
        self.button.create_in(self)
        
        self.pane = TabPane(self.id + '.pane', (0, 0))
        self.pane.create_in(self)
        self.pane.hide()
    
    def activate(self):
        self.button.lock_in()
        self.pane.show()
    
    def deactivate(self):
        self.button.release()
        self.pane.hide()
    
    def update_motion_dependent(self):
        super(TabPage, self).update_motion_dependent()
        
        self.button.update_motion_dependent()
        self.pane.update_motion_dependent()
    
    def on_update(self):
        self.button.update()
        self.pane.update()


class TabPane(PandaNodePath):
    items = ListAttribute(initiable = False)
    
    def add_item(self, item):
        self._items.append(item)
        
        item.create_in(self)
        
        return item
    
    def update_motion_dependent(self):
        super(TabPane, self).update_motion_dependent()
        
        for item in self.items:
            item.update_motion_dependent()
    
    def on_update(self):
        for item in self.items:
            item.update()

__all__ = [name for name in dir() if not name.startswith('_') or name == '_']
